package com.gitee.yannzh.rune.support.crud.service;

import cn.hutool.core.lang.Assert;
import com.alibaba.excel.read.listener.PageReadListener;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.gitee.yannzh.rune.common.util.BeanUtil;
import com.gitee.yannzh.rune.core.base.pagination.PageOption;
import com.gitee.yannzh.rune.core.base.pagination.PageResult;
import com.gitee.yannzh.rune.core.base.pojo.Entity;
import com.gitee.yannzh.rune.core.base.pojo.Param;
import com.gitee.yannzh.rune.core.base.pojo.VO;
import com.gitee.yannzh.rune.core.excel.ExcelUtil;
import com.gitee.yannzh.rune.core.exception.ServiceException;
import com.gitee.yannzh.rune.dao.base.mapper.IMapper;
import com.gitee.yannzh.rune.extension.mp.query.QueryHelper;
import com.gitee.yannzh.rune.support.crud.CrudHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.Serializable;
import java.util.Collection;
import java.util.List;


/**
 * @author yann
 * @date 2020/3/4
 * @description: 增强Service实现类封装
 */
public abstract class BaseServiceImpl<M extends IMapper<T>, T extends Entity, V extends VO>
        extends ServiceImpl<M, T> implements BaseService<T, V>, InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        CrudHelper.putService(getEntityClass(), this);
    }


    @Override
    public V getByKey(Serializable key) {
        return convertToBean(getById(key));
    }


    @Override
    public V get(Wrapper<T> wrapper) {
        return convertToBean(getOne(wrapper));
    }

    @Override
    public <Q extends Param> V get(Q query) {
        QueryWrapper<T> queryWrapper = QueryHelper.build(query, getEntityClass());
        return convertToBean(getOne(queryWrapper));
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<V> find(Wrapper<T> wrapper) {
        return listObjs(wrapper, e -> convertToBean((T) e));
    }

    @Override
    public <Q extends Param> List<V> find(Q query) {
        QueryWrapper<T> queryWrapper = QueryHelper.build(query, getEntityClass());
        return find(queryWrapper);
    }

    @Override
    public PageResult<V> pageList(IPage<T> page, Wrapper<T> wrapper) {
        page = page(page, wrapper);
        PageResult<T> pageResult = new PageResult<>();
        BeanUtils.copyProperties(page, pageResult);
        return pageResult.convert(this::convertToBean);
    }


    @Override
    public <Q extends Param> PageResult<V> pageList(Q query) {
        PageOption pageOption = query.ofPage();
        Page<T> page = pageOption.toPage(p -> Page.of(p.getPageNo(), p.getPageSize()));
        QueryWrapper<T> queryWrapper = QueryHelper.build(query, getEntityClass());
        return pageList(page, queryWrapper);
    }

    @SuppressWarnings("unchecked")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public <P extends Param> Serializable save(P param) {
        T entity = (param instanceof Entity) ? (T) param : convertToBean(param, getEntityClass());
        try {
            this.beforeSave(param);
            Assert.isTrue(save(entity), () -> new ServiceException("保存数据失败！"));
            this.afterSave(entity);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        TableInfo tableInfo = TableInfoHelper.getTableInfo(getEntityClass());
        return (Serializable) tableInfo.getPropertyValue(entity, tableInfo.getKeyProperty());
    }

    @SuppressWarnings("unchecked")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public <P extends Param> void updateById(P form) {
        try {
            this.beforeSave(form);
            T entity = (form instanceof Entity) ? (T) form : convertToBean(form, getEntityClass());
            Assert.isTrue(updateById(entity), () -> new ServiceException("更新数据失败！"));
            this.afterUpdate(entity);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @SuppressWarnings("unchecked")
    @Transactional(rollbackFor = Exception.class)
    @Override
    public <P extends Param> void update(P form, Wrapper<T> wrapper) {
        try {
            this.beforeUpdate(form);
            T entity = (form instanceof Entity) ? (T) form : convertToBean(form, getEntityClass());
            Assert.isTrue(update(entity, wrapper),
                    () -> new ServiceException("更新数据失败！"));
            this.afterUpdate(entity);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeByKey(Serializable key) {
        try {
            this.beforeRemove(key);
            Assert.isTrue(removeById(key),
                    () -> new ServiceException("删除数据失败！"));
            this.afterRemove(key);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void removeByKeys(Collection<? extends Serializable> keys) {
        removeBatchByIds(keys);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public <P extends Param> void remove(P param) {
        try {
            this.beforeRemove(param);
            if (param.getKeyValue() != null) {
                removeById(param.getKeyValue());
                return;
            }
            QueryWrapper<T> queryWrapper = QueryHelper.build(param, getEntityClass());
            Assert.isTrue(remove(queryWrapper),
                    () -> new ServiceException("删除数据失败！"));
            this.afterRemove(param);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <Q extends Param> void exportExcel(Q query, String fileName) {
        List<V> list = this.find(query);
        if (CollectionUtils.isEmpty(list)) {
            throw ServiceException.newInstance("导出数据为空");
        }
        if (ExcelUtil.hasTrans(getVoClass())) {
//            transService.transBatch(list);
        }
        ExcelUtil.export(fileName, "", getVoClass(), list);
    }


    @Override
    public <Q extends Param, E> void exportExcel(Q query, Class<E> clazz, String fileName) {
        T model = BeanUtil.copy(query, getEntityClass());
        List<T> list = list(Wrappers.lambdaQuery(model));
        List<E> data = BeanUtil.copyList(list, clazz);
        ExcelUtil.export(fileName, "", clazz, data);
    }

    @Override
    public void importExcel(MultipartFile file) {
        try {
            ExcelUtil.importExcel(file.getInputStream(), getVoClass(), new PageReadListener<>(
                    dataList -> {
                        if (!CollectionUtils.isEmpty(dataList)) {
//                            ExcelUtil.parseDict(dataList);
                            List<T> modelList = BeanUtil.copyList(dataList, getEntityClass());
                            saveBatch(modelList);
                        }
                    }));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}
